package com.weyoung.app.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.weyoung.app.controller.FileController;
import com.weyoung.app.dto.req.FamilyCultureDTO;
import com.weyoung.app.dto.req.FamilyCultureMessage;
import com.weyoung.app.service.UserService;
import com.weyoung.common.config.RabbitMQConfig;
import com.weyoung.common.consatant.exception.ServiceException;
import com.weyoung.common.consatant.result.Result;
import com.weyoung.common.model.entity.FamilyCulture;
import com.weyoung.app.service.FamilyCultureService;
import com.weyoung.app.mapper.FamilyCultureMapper;
import com.weyoung.common.model.entity.UserDO;
import com.weyoung.common.model.vo.app.FamilyCulturesVO;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.weyoung.common.consatant.errorcode.BaseErrorCode.SERVICE_ERROR;
import static com.weyoung.common.utils.RedisConstants.*;

/**
* @author 27675
* @description 针对表【family_culture(家族文化活动表)】的数据库操作Service实现
* @createDate 2025-04-17 14:31:36
*/
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class FamilyCultureServiceImpl extends ServiceImpl<FamilyCultureMapper, FamilyCulture>
        implements FamilyCultureService {

    private final UserService userService;
    private final Validator validator;
    private final StringRedisTemplate stringRedisTemplate;
    private final FamilyCultureMapper familyCultureMapper;
    private final FileController fileController;
    private final RabbitTemplate  rabbitTemplate;

    @Override
    public Result<FamilyCulture> addFamilyCulture(FamilyCultureDTO familyCultureDTO, MultipartFile coverImage,List<MultipartFile> images) {
        // 1. 参数校验
        validateFamilyCultureDTO(familyCultureDTO);

        // 2. 构建实体
        FamilyCulture familyCulture = buildFamilyCulture(familyCultureDTO,coverImage,images);

        // 3. 保存数据
        try {
            if (!save(familyCulture)) {
                log.error("家族文化保存失败，数据: {}", familyCulture);
                throw new ServiceException("家族文化保存失败");
            }

            log.info("家族文化新增成功，ID: {}, 创建人: {}",
                    familyCulture.getCultureId(), familyCulture.getCreatorId());
            // 删除列表缓存
            stringRedisTemplate.delete(FAMILY_CULTURE_LIST_KEY + familyCulture.getFamilyId());
            return Result.success(familyCulture);
        } catch (Exception e) {
            log.error("家族文化新增异常，数据: {}, 异常信息: {}",
                    familyCulture, e.getMessage(), e);
            throw new ServiceException("家族文化新增异常", e, SERVICE_ERROR);
        }
    }

    @Override
    public Result getFamilyCulture(String cultureId) {
        // 查找缓存是存在
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(FAMILY_CULTURE_KEY + cultureId))){
            // 缓存存在
            String JsonStr = stringRedisTemplate.opsForValue().get(FAMILY_CULTURE_KEY + cultureId);
            // 判断空值
            if (StrUtil.isBlank(JsonStr)){
                // 缓存为空
                return Result.failure("1","未找到对应家族文化记录");
            }
            // 缓存不为空
            FamilyCulture familyCulture = JSONUtil.toBean(JsonStr, FamilyCulture.class);
            // todo 异步增加浏览次数
            rabbitTemplate.convertAndSend(
                    RabbitMQConfig.FAMILY_CULTURE_EXCHANGE_NAME,
                    RabbitMQConfig.FAMILY_CULTURE_ROUTING_KEY,
                    buildFamilyCultureMessage(cultureId)
            );
            return Result.success(familyCulture);
        }
        // 缓存不存在，查找数据库
        QueryWrapper<FamilyCulture> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("culture_id", cultureId);
        FamilyCulture familyCulture = getOne(queryWrapper);
        // 如果数据库中不存在，返回失败
        if (familyCulture == null){
            stringRedisTemplate.opsForValue().set(FAMILY_CULTURE_KEY + cultureId,
                    "",
                    NULL_EXPIRE_TIME,
                    TimeUnit.MINUTES);
            return Result.failure("1","未找到对应家族文化记录");
        }
        // 数据库存在,存入缓存
        stringRedisTemplate.opsForValue().set(FAMILY_CULTURE_KEY + cultureId,
                JSONUtil.toJsonStr(familyCulture),
                FAMILY_CULTURE_EXPIRE_TIME,
                TimeUnit.MINUTES);
        // todo 异步增加浏览次数
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.FAMILY_CULTURE_EXCHANGE_NAME,
                RabbitMQConfig.FAMILY_CULTURE_ROUTING_KEY,
                buildFamilyCultureMessage(cultureId)
        );
        return Result.success(familyCulture);
    }

    private FamilyCultureMessage buildFamilyCultureMessage(String cultureId) {
        FamilyCultureMessage familyCultureMessage = new FamilyCultureMessage();
        familyCultureMessage.setCultureId(cultureId);
        return familyCultureMessage;
    }

    @Override
    public Result getFamilyCultureList() {
        // 获取用户信息
        UserDO userDO = getCurrentUser();
        if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(FAMILY_CULTURE_LIST_KEY + userDO.getFamilyId()))){
            // 缓存存在
            String JsonStr = stringRedisTemplate.opsForValue().get(FAMILY_CULTURE_LIST_KEY + userDO.getFamilyId());
            // 判断空值
            if (StrUtil.isBlank(JsonStr)){
                // 缓存为空
                return Result.failure("1","未找到对应家族文化记录");
            }
            List<FamilyCulturesVO> list = JSONUtil.toList(JsonStr, FamilyCulturesVO.class);
            return Result.success(list);
        }
        try {
            List<FamilyCulturesVO> list = familyCultureMapper.selecCultures(userDO.getFamilyId());
            if (list == null || list.isEmpty()){
                // 数据库未找到
                // 存入空数据入缓存
                stringRedisTemplate.opsForValue().set(FAMILY_CULTURE_LIST_KEY + userDO.getFamilyId(),
                        "",
                        NULL_EXPIRE_TIME,
                        TimeUnit.MINUTES);
                return Result.failure("1","未找到对应家族文化记录");
            }
            stringRedisTemplate.opsForValue().set(FAMILY_CULTURE_LIST_KEY + userDO.getFamilyId(),
                    JSONUtil.toJsonStr(list),
                    FAMILY_CULTURE_LIST_EXPIRE_TIME,
                    TimeUnit.MINUTES);
            return Result.success(list);
        } catch (Exception e) {
            log.error("获取家族文化列表异常，异常信息: {}", e.getMessage(), e);
            throw new ServiceException("获取家族文化列表异常", e, SERVICE_ERROR);
        }
    }

    /**
     * 校验家族文化DTO参数
     * @param familyCultureDTO 家族文化传输对象
     * @throws ServiceException 参数校验不通过时抛出
     */
    private void validateFamilyCultureDTO(FamilyCultureDTO familyCultureDTO) {
        if (familyCultureDTO == null) {
            throw new ServiceException("家族文化信息不能为空");
        }

        Set<ConstraintViolation<FamilyCultureDTO>> violations = validator.validate(familyCultureDTO);
        if (!violations.isEmpty()) {
            String message = violations.stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining("; "));
            throw new ServiceException("参数校验失败: " + message);
        }
    }

    /**
     * 构建家族文化实体
     * @param familyCultureDTO 家族文化传输对象
     * @return 家族文化实体
     * @throws ServiceException 构建失败时抛出
     */
    private FamilyCulture buildFamilyCulture(FamilyCultureDTO familyCultureDTO,MultipartFile coverImage,List<MultipartFile> images) {
        try {
            UserDO currentUser = getCurrentUser();
            // bean复杂
            FamilyCulture familyCulture = BeanUtil.copyProperties(familyCultureDTO, FamilyCulture.class);

            // 实体构建
            familyCulture.setCreatorId(currentUser.getUserId());
            familyCulture.setFamilyId(currentUser.getFamilyId());
            familyCulture.setCreateTime(LocalDateTime.now());
            familyCulture.setUpdateTime(LocalDateTime.now());
            familyCulture.setCultureId(generateCultureId());

            // 文件上传
            // 1、封面图片
            familyCulture.setCoverImage(generateCoverImageUrl(coverImage));
            // 2、图片列表
            familyCulture.setImageUrls(generateImageUrls(images));

            log.debug("构建家族文化实体成功，实体: {}", familyCulture);
            return familyCulture;
        } catch (Exception e) {
            log.error("构建家族文化实体失败，DTO: {}, 异常信息: {}",
                    familyCultureDTO, e.getMessage(), e);
            throw new ServiceException("构建家族文化实体失败", e, SERVICE_ERROR);
        }
    }

    /**
     * 获取当前登录用户信息
     * @return 用户实体
     * @throws ServiceException 获取用户失败时抛出
     */
    private UserDO getCurrentUser() {
        try {
            if (!StpUtil.isLogin()) {
                throw new ServiceException("用户未登录");
            }

            Integer userId = Integer.parseInt(StpUtil.getLoginId().toString());
            UserDO user = userService.getById(userId);

            if (user == null) {
                throw new ServiceException("用户不存在");
            }

            if (user.getFamilyId() == null) {
                throw new ServiceException("用户未关联家族");
            }

            return user;
        } catch (Exception e) {
            log.error("获取当前用户信息失败，异常信息: {}", e.getMessage(), e);
            throw new ServiceException("获取用户信息失败", e,SERVICE_ERROR);
        }
    }

    /**
     * 生成文化ID
     * @return 文化ID
     */
    private String generateCultureId() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 上传文化封面
     * @param coverImage
     * @return
     */
    private String generateCoverImageUrl(MultipartFile coverImage) {
        try {
            return fileController.uploadImage(coverImage);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 上传图片列表
     * @param images
     * @return
     */
    private List<String> generateImageUrls(List<MultipartFile> images) {
        try {
            return images.stream()
                    .map(image -> {
                        try {
                            return fileController.uploadImage(image);
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    })
                    .collect(Collectors.toList());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 异步增加浏览量（推荐方案）
    private void incrementViewCount(String cultureId, String familyId) {
        // 使用Redis原子操作先累加
        String countKey = "culture:view:" + cultureId;
        Long currentCount = stringRedisTemplate.opsForValue().increment(countKey);
        // 达到阈值或定时任务触发时持久化到数据库

        Long VIEW_COUNT_BATCH_SIZE = 5L;
        if (currentCount % VIEW_COUNT_BATCH_SIZE == 0) {
            updateViewCountToDB(cultureId, currentCount,familyId);
        }
    }

    @Transactional
    public void updateViewCountToDB(String cultureId, Long newCount, String familyId) {
        // 使用乐观锁避免并发问题
        FamilyCulture entity = new FamilyCulture();
        entity.setCultureId(cultureId);
        entity.setViewCount(newCount);
        updateById(entity);

        // 清除Redis中的计数
        stringRedisTemplate.delete("culture:view:" + cultureId);
        stringRedisTemplate.delete(FAMILY_CULTURE_LIST_KEY + familyId);
        stringRedisTemplate.delete(FAMILY_CULTURE_KEY + cultureId);
    }

}




















